import axios from "axios";
import { notification } from "ant-design-vue";
import store from "@/store";
import { getToken } from "xqjr-module-auth";
import { customAlphabet } from "nanoid";

const CancelToken = axios.CancelToken;
const nanoid = customAlphabet("0123456789abcdefghijklmnopqrstuvwxyz", 8);

// create an axios instance
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
  withCredentials: true, // send cookies when cross-domain requests
  timeout: 60000, // request timeout
  routeChangeCancel: true // 切换路由时是否取消
});

const params2Query = (params) => {
  if (!params) {
    return "";
  }
  const keys = Object.keys(params);
  let url = "?";
  for (const key of keys) {
    if (!(params[key] === null || params[key] === undefined)) {
      url += `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}&`;
    }
  }
  url = url.substring(0, url.length - 1);
  return url;
};

const cancelToken = [];

// request interceptor
service.interceptors.request.use(
  (config) => {
    // // 如果同样的请求存在，取消之前的请求，处理重复请求的话请求标示就得变，因为可能参数不一样，还可能post data不同
    // const requestUrl = `${config.method}_${config.url}_${JSON.stringify(config.params || {})}`;
    // const cancelIndex = cancelToken.findIndex((item) => item.url === requestUrl);
    // if (cancelIndex > -1) {
    //   cancelToken[cancelIndex].cancel();
    //   cancelToken.splice(cancelIndex, 1);
    // }
    const requestUrl = `${config.method}_${config.url}_${nanoid()}`;
    config.requestUrl = requestUrl;
    // 新请求加入 cancel token 配置，并存入本地缓存
    const source = CancelToken.source();
    config.cancelToken = source.token;

    cancelToken.push({
      url: requestUrl,
      cancel: source.cancel,
      routeChangeCancel: config.routeChangeCancel === undefined ? true : config.routeChangeCancel
    });

    config.headers.deviceType = store.state.settings.deviceType || "web";
    config.headers["token"] = getToken();
    if (config.method === "post") {
      if (typeof config.data === "string" && config.data.indexOf("=") === -1) {
        config.data = JSON.stringify(config.data);
        config.headers["Content-Type"] = "application/json;charset=UTF-8";
      }
    } else if (config.method === "get") {
      config.url = config.url + params2Query(config.params);
      config.params = {};
    }
    return config;
  },
  (error) => {
    console.log("debug log --> ", error);
    return Promise.reject("请求失败");
  }
);

const responseDeleteCancelToken = (config) => {
  // 成功的请求从本地缓存中清掉
  const cancelIndex = cancelToken.findIndex((item) => item.url === config.requestUrl);
  if (cancelIndex > -1) {
    cancelToken.splice(cancelIndex, 1);
  }
};

// response interceptor
service.interceptors.response.use(
  (response) => {
    responseDeleteCancelToken(response.config);

    if (response.data) {
      if (response.data.code === 401) {
        store
          .dispatch("auth/refreshToken")
          .then(() => {
            localStorage.setItem("refreshStatus", "done");
          })
          .catch(() => {
            setTimeout(() => {
              store.dispatch("auth/resetToken").then(() => {
                location.reload();
              });
            }, 1000);
          });
      } else if (response.data.code === 403) {
        switch (response.data.data) {
          case "check":
            store
              .dispatch("auth/refreshToken")
              .then(() => {
                localStorage.setItem("refreshStatus", "done");
                notification.warning({
                  message: "提示",
                  description: "请求提交失败，请重新提交"
                });
              })
              .catch(() => {
                localStorage.setItem("refreshStatus", "done");
                notification.warning({
                  message: "警告",
                  description: "登录已失效，即将跳转到登录页面"
                });
                setTimeout(() => {
                  store.dispatch("auth/resetToken").then(() => {
                    location.reload();
                  });
                }, 2000);
              });
            break;
          case "refresh":
            setTimeout(() => {
              store.dispatch("auth/resetToken").then(() => {
                location.reload();
              });
            }, 2000);
            break;
          default:
            notification.warning({
              message: "警告",
              description: response.data.msg
            });
            break;
        }
      } else if (response.data.code === 200) {
        if (response.data.success) {
          return response.data;
        } else {
          if (!response.config?.noNotification) {
            notification.error({
              message: "失败",
              description: response.data.msg || "请求失败"
            });
          }
          return Promise.reject(new Error(response.data.msg || "请求失败"));
        }
      } else if (response.data.code === 400) {
        const reqStatus = localStorage.getItem("reqStatus");
        if (reqStatus === "400") {
          return Promise.reject(new Error(response.data.msg || "参数错误"));
        }
        localStorage.setItem("reqStatus", "400");
        const timer = setTimeout(() => {
          localStorage.removeItem("reqStatus");
          clearTimeout(timer);
        }, 2000);
        notification.error({
          message: "失败",
          description: response.data.success === false ? response.data.msg || "参数错误" : "参数错误"
        });
        if (response.data.msg === "当前登录租户已到期，请联系管理员续期后重试") {
          store.commit("hr/setAdminNavState", "workbench");
          localStorage.removeItem("isFirstLogin");
          store.dispatch("auth/logout");
          this.$router.push(`/auth/login`);
        }
        return Promise.reject(new Error(response.data.msg || "参数错误"));
      } else if (response.data.code === 101) {
        // 租户已过期
        if (response.data.data) {
          notification.error({
            message: "提示",
            description: response.data.msg
          });
          // TODO 这里查一下有没有返回租户名称，有的话把租户名称也传过去
          store
            .dispatch("auth/switchSite", response.data.data)
            .then(() => {
              localStorage.setItem("switchSite", "true");
              localStorage.setItem("siteId", response.data.data);
              setTimeout(function () {
                location.reload();
              }, 1900);
            })
            .catch((err) => {
              console.log("debug log --> ", err);
            });
        } else {
          store.commit("hr/setAdminNavState", "workbench");
          localStorage.removeItem("isFirstLogin");
          store.dispatch("auth/logout");
          this.$router.push(`/auth/login`);
        }
      } else {
        const reqStatus = localStorage.getItem("reqStatus");
        if (reqStatus === "500") {
          return Promise.reject(new Error(response.data.msg || "请求失败"));
        }
        localStorage.setItem("reqStatus", "500");
        const timer = setTimeout(() => {
          localStorage.removeItem("reqStatus");
          clearTimeout(timer);
        }, 2000);
        const msg = response.data.success === false ? response.data.msg || "请求失败" : "请求失败";
        notification.error({
          message: "失败",
          description: msg
        });
        return Promise.reject(new Error(msg));
      }
    } else {
      return Promise.reject(new Error("请求失败"));
    }
  },
  (error) => {
    if (axios.isCancel(error)) {
      error.selfCancel = true;
    }
    // 如果是自己取消的请求，不用处理
    if (!error.selfCancel) {
      if (error.response) {
        responseDeleteCancelToken(error.response.config);
        if (error.response.status === 401) {
          const reqStatus = localStorage.getItem("reqStatus");
          if (reqStatus === "401") {
            return Promise.reject(error);
          }
          localStorage.setItem("reqStatus", "401");
          const timer = setTimeout(() => {
            localStorage.removeItem("reqStatus");
            clearTimeout(timer);
          }, 2000);
          if (error.response.data.data === "kicked") {
            notification.warning({
              message: "警告",
              description: error.response.data.msg
            });
            setTimeout(() => {
              store.dispatch("auth/resetToken").then(() => {
                location.reload();
              });
            }, 2000);
          } else {
            store
              .dispatch("auth/refreshToken")
              .then(() => {
                localStorage.setItem("refreshStatus", "done");
                if (error.response.config.method === "get") {
                  notification.warning({
                    message: "提示",
                    description: "登录已过期，将刷新页面"
                  });
                  location.reload();
                } else {
                  notification.warning({
                    message: "提示",
                    description: "登录已过期，请重新提交"
                  });
                }
              })
              .catch(() => {
                localStorage.setItem("refreshStatus", "done");
                // notification.warning({
                //   message: "警告",
                //   description: "登录已失效，即将跳转到登录页面"
                // });
                setTimeout(() => {
                  store.dispatch("auth/resetToken").then(() => {
                    location.reload();
                  });
                }, 2000);
              });
          }
        } else if (error.response.status === 403) {
          notification.warning({
            message: "警告",
            description: "没有操作权限"
          });
        } else if (error.response.status === 502) {
          const reqStatus = localStorage.getItem("reqStatus");
          if (reqStatus === "502") {
            return Promise.reject(new Error(error.response.data.msg || "服务器发生错误"));
          }
          localStorage.setItem("reqStatus", "502");
          const timer = setTimeout(() => {
            localStorage.removeItem("reqStatus");
            clearTimeout(timer);
          }, 2000);
          notification.error({
            message: "失败",
            description: "服务器发生错误"
          });
        } else {
          notification.error({
            message: "失败",
            description: error.message || "请求失败"
          });
        }
      } else if (error.request) {
        notification.error({
          message: "错误",
          description: error.message || "请求发送错误"
        });
      } else {
        notification.error({
          message: "错误",
          description: error.message
        });
      }

      return Promise.reject(error);
    } else {
      return Promise.reject(error);
    }
  }
);

export default service;

export { cancelToken };
